import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { useUserStore } from '@/stores/modules/user'
import { getToken } from './auth'
import router from '@/router'

// 请求超时时间
const timeout = 60000

// 创建axios实例
const service: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
  timeout,
  headers: {
    'Content-Type': 'application/json;charset=UTF-8',
  },
})

// 请求队列
const pendingMap = new Map()

// 生成请求key
const generateReqKey = (config: AxiosRequestConfig) => {
  const { method, url, params, data } = config
  return [method, url, JSON.stringify(params), JSON.stringify(data)].join('&')
}

// 添加请求
const addPending = (config: AxiosRequestConfig) => {
  const requestKey = generateReqKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken(cancel => {
      if (!pendingMap.has(requestKey)) {
        pendingMap.set(requestKey, cancel)
      }
    })
}

// 移除请求
const removePending = (config: AxiosRequestConfig) => {
  const requestKey = generateReqKey(config)
  if (pendingMap.has(requestKey)) {
    const cancelToken = pendingMap.get(requestKey)
    cancelToken(requestKey)
    pendingMap.delete(requestKey)
  }
}

// 加载实例
let loadingInstance: any = null

// 显示加载
const showLoading = (text = '加载中...') => {
  loadingInstance = ElLoading.service({
    text,
    spinner: 'el-icon-loading',
    background: 'rgba(0, 0, 0, 0.7)',
  })
}

// 隐藏加载
const hideLoading = () => {
  if (loadingInstance) {
    loadingInstance.close()
    loadingInstance = null
  }
}

// 响应数据接口
export interface ResponseData<T = any> {
  code: number
  msg: string
  data: T
  traceId?: string
  timestamp?: number
}

// 请求配置扩展接口
export interface RequestConfig extends AxiosRequestConfig {
  showLoading?: boolean
  showError?: boolean
  showSuccess?: boolean
  successMsg?: string
  errorMsg?: string
  repeatRequest?: boolean
}

// 请求拦截器
service.interceptors.request.use(
  (config: RequestConfig) => {
    // 移除重复请求
    if (!config.repeatRequest) {
      removePending(config)
      addPending(config)
    }

    // 添加token
    const token = getToken()
    if (token) {
      config.headers = config.headers || {}
      config.headers['Authorization'] = `Bearer ${token}`
    }

    // 添加链路追踪ID
    const traceId = generateTraceId()
    config.headers = config.headers || {}
    config.headers['X-Trace-Id'] = traceId

    // 显示加载
    if (config.showLoading) {
      showLoading()
    }

    return config
  },
  (error: AxiosError) => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse<ResponseData>) => {
    const config = response.config as RequestConfig
    
    // 移除请求
    removePending(config)
    
    // 隐藏加载
    if (config.showLoading) {
      hideLoading()
    }

    const { code, msg, data } = response.data

    // 成功响应
    if (code === 200) {
      // 显示成功消息
      if (config.showSuccess) {
        ElMessage.success(config.successMsg || msg || '操作成功')
      }
      return response.data
    }

    // 业务错误
    handleBusinessError(code, msg, config)
    return Promise.reject(new Error(msg || '请求失败'))
  },
  (error: AxiosError) => {
    const config = error.config as RequestConfig
    
    // 移除请求
    if (config) {
      removePending(config)
    }
    
    // 隐藏加载
    if (config?.showLoading) {
      hideLoading()
    }

    // 处理HTTP错误
    handleHttpError(error, config)
    return Promise.reject(error)
  }
)

// 处理业务错误
const handleBusinessError = (code: number, msg: string, config?: RequestConfig) => {
  switch (code) {
    case 401:
      ElMessageBox.confirm('登录状态已过期，请重新登录', '系统提示', {
        confirmButtonText: '重新登录',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        const userStore = useUserStore()
        userStore.logoutAction()
      })
      break
    case 403:
      ElMessage.error('权限不足，无法访问')
      break
    case 404:
      ElMessage.error('请求的资源不存在')
      break
    case 429:
      ElMessage.warning('请求过于频繁，请稍后再试')
      break
    case 500:
      ElMessage.error('服务器内部错误')
      break
    case 601:
      ElMessage.warning(msg || '操作警告')
      break
    default:
      if (config?.showError !== false) {
        ElMessage.error(config?.errorMsg || msg || '操作失败')
      }
  }
}

// 处理HTTP错误
const handleHttpError = (error: AxiosError, config?: RequestConfig) => {
  let message = '网络错误'
  
  if (error.code === 'ECONNABORTED') {
    message = '请求超时，请稍后重试'
  } else if (error.response) {
    const status = error.response.status
    switch (status) {
      case 400:
        message = '请求参数错误'
        break
      case 401:
        message = '未授权，请重新登录'
        handleBusinessError(401, message)
        return
      case 403:
        message = '权限不足'
        break
      case 404:
        message = '请求地址不存在'
        break
      case 500:
        message = '服务器内部错误'
        break
      case 502:
        message = '网关错误'
        break
      case 503:
        message = '服务不可用'
        break
      case 504:
        message = '网关超时'
        break
      default:
        message = `连接错误${status}`
    }
  } else if (error.request) {
    message = '网络连接失败'
  }

  if (config?.showError !== false) {
    ElMessage.error(config?.errorMsg || message)
  }
}

// 生成链路追踪ID
const generateTraceId = (): string => {
  return 'trace-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9)
}

// 请求方法封装
class Request {
  /**
   * GET请求
   */
  get<T = any>(url: string, params?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return service.get(url, { params, ...config })
  }

  /**
   * POST请求
   */
  post<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return service.post(url, data, config)
  }

  /**
   * PUT请求
   */
  put<T = any>(url: string, data?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return service.put(url, data, config)
  }

  /**
   * DELETE请求
   */
  delete<T = any>(url: string, params?: any, config?: RequestConfig): Promise<ResponseData<T>> {
    return service.delete(url, { params, ...config })
  }

  /**
   * 上传文件
   */
  upload<T = any>(url: string, file: File, onProgress?: (progress: number) => void): Promise<ResponseData<T>> {
    const formData = new FormData()
    formData.append('file', file)
    
    return service.post(url, formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
      onUploadProgress: (progressEvent) => {
        if (progressEvent.total && onProgress) {
          const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
          onProgress(progress)
        }
      },
    })
  }

  /**
   * 下载文件
   */
  download(url: string, params?: any, filename?: string): Promise<void> {
    return service.get(url, {
      params,
      responseType: 'blob',
    }).then((response: any) => {
      const blob = new Blob([response.data])
      const downloadUrl = window.URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = downloadUrl
      link.download = filename || 'download'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.URL.revokeObjectURL(downloadUrl)
    })
  }
}

export default new Request()

// 导出axios实例
export { service }
